/*
 * @Author: rock
 * @Date: 2025-05-23 22:01:45
 * @LastEditors: rock 
 * @LastEditTime: 2025-05-25 16:04:34
 * @FilePath: /002ThreadPool/include/threadpool.h
 * @Description: Ctrl+Num1-> For Document; Ctrl+Num2-> For Function
 *
 * Copyright (c) 2025 by rock, All Rights Reserved.
 */

#ifndef _THREADPOOL_H
#define _THREADPOOL_H

#include "global.h"

#include <queue> //任务队列
#include <memory>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <thread>
#include <chrono>

// Any类型, 接收任意数据类型
// 这个实现使用了类型擦除技术，通过基类指针存储任意类型的数据
class Any
{
public:
    Any() = default;
    ~Any() = default;
    Any(const Any &) = delete;
    // Any &operator=(const Any &) = default;
    // Any(Any &&) = default;
    // 移动构造函数
    Any(Any&& other) noexcept : base_(std::move(other.base_)) {}
    // 移动赋值运算符
    Any& operator=(Any&& other) noexcept {
        base_ = std::move(other.base_);
        return *this;
    }

    // 这个构造类型可以让Any类型接收任意的其他数据类型
    template <typename T>
    Any(T data) : base_(new Derive<T>(data)){}

    // 这个方法能把Any对象里面存储的data数据提取出来
    template <typename T>
    T cast_()
    {
        // 返回任意数据类型
        // 怎么从base_找到他的指向的Derive对象, 从他里面取出data数据
        // 基类指针转成派生类指针 RTTI
        Derive<T> *pd = dynamic_cast<Derive<T> *>(base_.get());
        if (pd == nullptr)
        {
            LOG("返回时的数据类型转换错误");
            throw "type is error";
        }
        return pd->data_;
    }

private:
    // 基类类型
    class Base
    {
    public:
        virtual ~Base() = default;
    };
    // 派生类类型
    template <typename T>
    class Derive : public Base
    {
    public:
        Derive(T data) : data_(data) {}

    
        T data_;
    };

private:
    // 定义一个基类的指针
    std::unique_ptr<Base> base_;
};

// 实现一个信号量, 进行线程间通信
class Semaphore
{
public:
    Semaphore()
        : resLimit_(0)
    {
    }

    ~Semaphore() = default;

    // 获取一个信号量资源
    void wait()
    {
        std::unique_lock<std::mutex> lock(mtx_);

        // 等待信号量资源, 没有资源的话阻塞线程
        cond_.wait(lock, [&]() -> bool
                   { return resLimit_ > 0; }); // 资源计数大于0的时候解除阻塞
        resLimit_--;                           // 资源计数减减
    }

    // 增加一个信号量资源
    void post()
    {
        std::unique_lock<std::mutex> lock(mtx_);
        resLimit_++;

        // 通知
        cond_.notify_all();
    }

private:
    int resLimit_;                 //
    std::mutex mtx_;               // 使用mutex锁来实现线程间通信
    std::condition_variable cond_; // 条件变量, 互斥锁+条件变量来实现信号量
};
class Task;
// 实现接收提交到线程池的task任务执行完成后的返回值类型Result
class Result
{
public:

    Result(std::shared_ptr<Task> task, bool isValid = true);
    ~Result() = default;

    Result(Result&& other) noexcept ;

    Any get()
    {
        if(!isValid_)
        {
            return "";
        }

        //task任务如果没有执行完, 阻塞用户线程
        sem_.wait();
        return std::move(any_);
    }

    void setVal(Any any)
    {
        //存储task的返回值
        this->any_ = std::move(any);
        sem_.post();
    }

private:
    Any any_;                    // 存储返回值
    Semaphore sem_;              // 信号量, 线程通信使用
    std::shared_ptr<Task> task_; // 指向对应获取返回值的任务对象
    std::atomic_bool isValid_;    // 返回值是否有效, 如果任务提交的时候是失败的, 那么这个返回值也是无效的
};

// 任务抽象基类
// 自己的任务继承这个基类, 重写run方法来处理自己的具体任务
// 任务队列中的任务, 是要在调用完run函数后才能析构
class Task
{
public:
    Task();
    ~Task() = default;
    // 用户可以自定义任意任务类型 , 从Task继承而来, 重写run方法, 实现自定义任务处理
    // 模板和虚函数不能放在一起
    virtual Any run() = 0;
    void exec();
    void setResult(Result* res);

private:
    Result* result_;
};

// 线程池支持两种模式
enum class PoolMode
{
    MOD_FIXED,  // 固定数量的线程
    MOD_CACHED, // 线程数量可动态增长模式
};

// 线程池中的线程类型
class Thread
{
public:
    // 线程池中线程绑定的线程函数, 因为需要访问线程池的部分参数, 绑定函数对象后, 可以直接使用线程池的参数
    // 对应的是ThreadPool下的void threadFunc();
    // 线程函数对象类型
    using ThreadFunc = std::function<void(int)>;

    // Thread构造
    Thread(ThreadFunc func, int id);
    // Thread析构
    ~Thread();

    // 启动线程
    void start();

private:
    ThreadFunc func_; // 线程池的函数对象
    int id_;          // 线程池中的id
};

/**
 * example:
 *      ThreadPool pool;
 *      pool.start(4);
 *
 *      class MyTask : public Task
 *      {
 *          public:
 *              void run();//继承Task任务类, 重写run方法
 *      };
 *
 *      pool.submitTask(std::make_shared<MyTask>()); // 提交用户自己的任务
 *
 *
 * **/

// 线程池类型
class ThreadPool
{
public:
    // 构造
    ThreadPool();

    // 析构
    ~ThreadPool();

    // 设置线程池工作的增长模式
    void setMode(PoolMode mode);

    // 设置task任务队列上限阈值
    void setTaskQueMaxThreshHold(int threshhold);

    // 给线程池提交任务
    Result submitTask(std::shared_ptr<Task> sp);

    // 开启线程池
    void start(int initThreadSize = 4);

    // 禁用线程池的拷贝构造和赋值构造
    ThreadPool(const ThreadPool &) = delete;
    ThreadPool &operator=(const ThreadPool &) = delete;

private:
    // 定义线程函数
    void threadFunc(int id);

private:
    // std::vector<Thread *> threads_; // 线程列表
    std::vector<std::unique_ptr<Thread>> threads_;
    size_t initThreadSize_; // 初始的线程数量

    std::queue<std::shared_ptr<Task>> taskQue_; // 任务队列
    std::atomic_int taskSize_;                  // 任务队列中的任务数量, 消费者消费一个任务, 数量减减, 生产者生产一个任务, 数量加加, 保证任务队列的线程安全
    size_t taskQueMaxThreshHold_;               // 阈值, 自定义任务数量最大上限
    std::mutex taskQueMtx_;                     // 保证任务队列的线程安全
    std::condition_variable notFull_;           // 表示任务队列不满
    std::condition_variable notEmpty_;          // 表示任务队列不空 C++库里面的很多函数是前面加_ , 尽量后面加_来保证

    PoolMode poolMode_;                // 当前线程池的增长模式
    static size_t count_tasks_;        // 任务计数
    static size_t count_submit_tasks_; // 提交任务计数
};

#endif
